Automatyzacja procesów analizy danych jest kluczowa w wielu dziedzinach, od biznesu po nauki społeczne i medycynę. Z rosnącym wolumenem danych oraz złożonością analizowanych problemów, automatyzacja staje się coraz bardziej niezbędna. Pozwala ona efektywnie zarządzać danymi, przyspieszać cykl rozwoju modeli, eliminować błędy ludzkie oraz zwiększać skuteczność analizy.
Jest to zestaw narzędzi do modelowania danych w R, które obejmują szereg pakietów, takich jak parsnip do definiowania modeli, recipes do przetwarzania wstępnego danych, workflows do organizowania procesów modelowania, tune do strojenia hiperparametrów i inne.
library(tidymodels)
## ── Attaching packages ────────────────────────────────────── tidymodels 1.1.1 ──
## ✔ broom 1.0.5 ✔ recipes 1.0.10
## ✔ dials 1.2.1 ✔ rsample 1.2.0
## ✔ ggplot2 3.5.0 ✔ tibble 3.2.1
## ✔ infer 1.0.6 ✔ tidyr 1.3.1
## ✔ modeldata 1.3.0 ✔ tune 1.2.1
## ✔ parsnip 1.2.0 ✔ workflows 1.1.4
## ✔ purrr 1.0.2 ✔ workflowsets 1.0.1
## ── Conflicts ───────────────────────────────────────── tidymodels_conflicts() ──
## ✖ purrr::discard() masks scales::discard()
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ✖ recipes::step() masks stats::step()
## • Learn how to get started at https://www.tidymodels.org/start/
Workflow to obiekt, który może łączyć ze sobą żądania dotyczące
przetwarzania wstępnego, modelowania oraz przetwarzania końcowego. Na
przykład, jeśli mamy receptę (recipe) i model
parsnip, mogą one być połączone w workflow. Zalety to:
Nie ma potrzeby śledzenia osobnych obiektów w swoim środowisku roboczym.
Przygotowanie recepty i dopasowanie modelu można wykonać za
pomocą pojedynczego wywołania funkcji fit().
library(recipes)
library(parsnip)
library(workflows)
Pipelines są prostym sposobem na zachowanie uporządkowanego kodu przetwarzania danych i modelowania. Konkretnie, pipeline łączy kroki przetwarzania danych i modelowania, dzięki czemu możemy używać całego zestawu jak jednego kroku.
%>% lub |>
Zalety:
Czystszy kod: Dzięki nim nie trzeba ręcznie śledzić danych na każdym etapie przetwarzania.
Mniej błędów: Mniejsze ryzyko pominięcia lub źle zastosowania kroków przetwarzania danych.
Zbiór danych zawiera informacje dotyczące nieruchomości w Melbourne, Australii. Dane te zostały zebrane przez Tony’ego Pino z publicznie dostępnych wyników opublikowanych co tydzień na stronie Domain.com.au. Zbiór obejmuje adresy nieruchomości, rodzaj nieruchomości, dzielnicę, metodę sprzedaży, liczbę pokoi, cenę, agenta nieruchomości, datę sprzedaży oraz odległość od centrum miasta.
data <- read.csv("melb_data.csv")
head(data)
# Podział danych na zbiór treningowy i testowy
set.seed(0)
train_index <- sample(1:nrow(data), 0.8 * nrow(data)) # Indeksy wierszy dla zbioru treningowego
X_train_full <- data[train_index, ]
X_valid_full <- data[-train_index, ]
y_train <- X_train_full$Price
y_valid <- X_valid_full$Price
# Wybór kolumn kategorycznych i numerycznych
categorical_cols <- names(Filter(is.character, X_train_full)) #kolumny kategoryczne z zbioru treningowego
numerical_cols <- names(Filter(is.numeric, X_train_full)) #kolumny numeryczne z zbioru treningowego
# Wybór kolumn z niską kardynalnością (czyli stosunkowo niską liczbą unikalnych wartości <10 w tym przypadku)
selected_categorical_cols <- character()
for (col in categorical_cols) {
if (length(unique(X_train_full[[col]])) < 10) {
selected_categorical_cols <- c(selected_categorical_cols, col)
}
}
# Stworzenie zbiorów treningowego i testowego zawierających wybrane kolumny
X_train <- X_train_full[c(selected_categorical_cols, numerical_cols)]
X_valid <- X_valid_full[c(selected_categorical_cols, numerical_cols)]
head(X_train)
Najpierw definiujemy kroki przetwarzania danych, następnie określamy specyfikację modelu, łączymy je w workflow oraz dopasowujemy model i dokonujemy oceny jego działania. Całość odbywa się w sposób uporządkowany i spójny, co ułatwia zarządzanie i analizę danych w kontekście modelowania.
# Definicja preprocessingu
rec <- recipe(Price ~ ., data = X_train) %>%
step_impute_median(all_numeric(), -all_outcomes()) %>%
step_other(all_nominal(), -all_outcomes(), threshold = 0.05) %>%
step_dummy(all_nominal(), -all_outcomes())
# Definicja modelu
model_spec <- rand_forest(trees = 100) %>%
set_mode("regression") %>%
set_engine("randomForest")
# Tworzenie potoku
wflow <- workflow() %>%
add_recipe(rec) %>%
add_model(model_spec)
# Dopasowanie modelu
fit <- fit(wflow, data = X_train)
# Predykcje
preds <- predict(fit, new_data = X_valid)$.pred
##
## Dołączanie pakietu: 'Metrics'
## Następujące obiekty zostały zakryte z 'package:yardstick':
##
## accuracy, mae, mape, mase, precision, recall, rmse, smape
MAE_score <- mae(y_valid, preds)
RMSE_score <- rmse(y_valid, preds)
MAPE_score <- mape(y_valid, preds)
print(paste('MAE:', MAE_score))
## [1] "MAE: 168048.412293939"
print(paste('RMSE:', RMSE_score))
## [1] "RMSE: 312653.715323329"
print(paste('MAPE:', MAPE_score))
## [1] "MAPE: 0.150332771446798"
# Tworzenie ramki danych z prawdziwymi i przewidywanymi wartościami
data_ <- data.frame(truth = y_valid, estimate = preds)
data_$residuals <- round(data_$truth - data_$estimate, 2)
library(plotly)
##
## Dołączanie pakietu: 'plotly'
## Następujący obiekt został zakryty z 'package:ggplot2':
##
## last_plot
## Następujący obiekt został zakryty z 'package:stats':
##
## filter
## Następujący obiekt został zakryty z 'package:graphics':
##
## layout
# Tworzenie interaktywnego wykresu residuów za pomocą plotly
plot_ly(data_, x = ~estimate, y = ~residuals, type = "scatter", mode = "markers",
marker = list(color = ~residuals, colorscale = "Viridis"),
text = ~paste("Przewidywane wartości: ", round(estimate, 2), "<br>",
"Residua: ", residuals),
hoverinfo = "text") %>%
layout(title = "Wykres residuów",
xaxis = list(title = "Przewidywane wartości"),
yaxis = list(title = "Residua"))
sum(abs(data_$residuals) < 1000)
## [1] 18
data_ %>% filter(abs(data_$residuals) < 1000)